package backup

import (
	"github.com/rs/zerolog/log"
	apiv1 "gomod.alauda.cn/mysql-mgr-operator/api/v1"
	apiv1a1 "gomod.alauda.cn/mysql-mgr-operator/api/v1alpha1"
	corev1 "k8s.io/api/core/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	"sigs.k8s.io/controller-runtime/pkg/client"
)

type CreateOption struct {
	Preserving bool
	Cluster    string
	Type       string
	Way        string
	Secret     string
	Endpoint   string
	Region     string
	Bucket     string
	Databases  []string
}

type Create struct {
	*CreateOption
	*Base
}

func NewCreate(option *CreateOption) *Create {
	return &Create{
		CreateOption: option,
	}
}

func (c *Create) WithBase(base *Base) *Create {
	c.Base = base
	return c
}

func (c *Create) Run() error {
	var backupCr client.Object
	if c.Version == "v1" {
		backupCr = c.buildV1Template()
	} else {
		backupCr = c.buildV1A1Template()
	}
	err := c.create(backupCr)
	if c.Preserving || !apierrors.IsAlreadyExists(err) {
		return err
	}
	log.Warn().Str("name", c.Name).Str("namespace", c.Namespace).Msg("backup already exists, try to recreate it")
	err = c.delete(backupCr)
	if err != nil {
		return err
	}
	err = c.create(backupCr)
	if err != nil {
		return err
	}
	return nil
}

func (c *Create) buildV1Template() *apiv1.MySQLBackup {
	backupCr := defaultV1Backup.DeepCopy()
	backupCr.Name = c.Name
	backupCr.Namespace = c.Namespace
	backupCr.Spec.Cluster.Name = c.Cluster
	backupCr.Spec.Type = apiv1.BackupType(c.Type)
	backupCr.Spec.Way = apiv1.BackupWay(c.Way)
	backupCr.Spec.Storage.S3 = &apiv1.S3{
		Secret:   &corev1.LocalObjectReference{Name: c.Secret},
		Region:   c.Region,
		Endpoint: c.Endpoint,
		Bucket:   c.Bucket,
	}
	return backupCr
}

func (c *Create) buildV1A1Template() *apiv1a1.MySQLBackup {
	backupCr := defaultV1A1Backup.DeepCopy()
	backupCr.Name = c.Name
	backupCr.Namespace = c.Namespace
	backupCr.Spec.Cluster.Name = c.Cluster
	backupCr.Spec.StorageProvider.S3 = &apiv1a1.S3StorageProvider{
		CredentialsSecret: &corev1.LocalObjectReference{Name: c.Secret},
		Region:            c.Region,
		Endpoint:          c.Endpoint,
		Bucket:            c.Bucket,
	}
	if c.Type == string(apiv1.TypeOfBackupIncr) {
		backupCr.Spec.Executor.UseBinlog = true
		backupCr.Spec.Executor.MySQLBinlog = &apiv1a1.MySQLBinlogBackupExecutor{
			Compression: "gzip",
			SpecOpt: apiv1a1.MySQLBinlogOption{
				StartGTID: "",
				Index:     0,
			},
		}
	}
	databases := make([]apiv1a1.Database, 0)
	for _, name := range c.Databases {
		databases = append(databases, apiv1a1.Database{Name: name})
	}
	backupCr.Spec.Executor.MySQLDump = &apiv1a1.MySQLDumpBackupExecutor{
		Databases: databases,
	}
	return backupCr
}
